# from cmcc import parse_html
import asyncio
import base64
import hashlib
import json
import random
import sys
import time
import urllib
from datetime import datetime

import aiohttp
import aioredis
import motor
from faker import Faker

from baseHandler import init_logger
from cmcc import query
from util import aes
import logging

def get_ts():
    return str(time.time()).replace('.', '')[:13]

async def aget_result(orderid):
    faker = Faker(locale='zh_CN')
    ip = faker.ipv4()
    headers = {
        'User-Agent': faker.chrome(),
        'CLIENT-IP': ip,
        'X-FORWARDED-FOR': ip,
    }
    redis = await aioredis.create_redis(address=('localhost', 6379), db=0, loop=loop)
    proxys = await redis.smembers('proxy', encoding='utf-8')
    redis.close()
    await redis.wait_closed()
    proxy = random.choice(list(proxys))
    if proxy:
        conn = proxy
    else:
        conn = None
    async with aiohttp.ClientSession(headers=headers) as session:
        url = 'https://pay.shop.10086.cn/paygw/fnpay/%s-20.html' % orderid
        async with session.get(url, proxy=conn) as resp:
            if resp.status != 200:
                logger.error(resp.status)
                return '8', '请求出错'
            query_url = str(resp.url)
        params = urllib.parse.urlparse(query_url).query
        params = '%s&_=%s' % (params, get_ts())
        url = 'https://shop.10086.cn/i/v1/pay/paycallback?'+ params
        headers['Host'] = 'shop.10086.cn'
        headers['Referer'] = query_url
        headers['X-Requested-With'] =  'XMLHttpRequest'
        async with session.get(url, proxy=conn) as resp:
            res_rsp = await resp.json()
            if res_rsp['data']['status'] == '0':
                orderstate = '0'
            else:
                orderstate = '8'
            return orderstate, res_rsp['data']['payDate']


def encrypt(aes_key, data):
    data = json.dumps(data)
    crypto = aes.AesEncryption(aes_key)
    data = crypto.encrypt(data)
    return base64.urlsafe_b64encode(data).decode("utf-8")


def niti_data(aeskey, sha_key, notify_data, result):
    encrypt_text = encrypt(aeskey, notify_data)
    merchantid = result["MERCHANTID"]
    timestamp = result.get("RESPTIME", datetime.now().strftime('%Y%m%d%H%M%S'))
    sign_string = sha_key + merchantid + encrypt_text + timestamp + sha_key
    sign = hashlib.sha256(sign_string.encode("utf-8")).hexdigest()
    request_obj = {
        "merchantid": merchantid,
        "data": encrypt_text,
        "sign": sign,
        "timestamp": timestamp
    }
    return request_obj


# 通知支付方
async def noti_user(notify_url, merchantid, data, orderstate, message):
    if notify_url:
        outer_orderno = data.get("ordernumber")
        # merchantid = data.get("merchantuid")
        merchant_info = await db.merchant.find_one({"merchantid": merchantid})
        aeskey = merchant_info['AESKEY']
        shakey = merchant_info['SHAKEY']
        notify_data = {
            "ordernumber": data["ordernumber"],
            "payorderno": data.get("payorderno", ""),
            "orderid": data.get("orderid", ""),
            "orderstate": orderstate,
            "message": message,
        }
        request_obj = niti_data(aeskey, shakey, notify_data, {'MERCHANTID': merchantid})
        for i in range(5):

            async with aiohttp.ClientSession() as session:
                async with session.post(notify_url, data=request_obj) as rsp:
                    body = await rsp.text()
                    logger.info(body)
            if rsp.status == 200 and body in ('SUCCESS', 'success'):
                logger.info("支付方%s|%s收到下游成功应答|订单号%s", i, outer_orderno, data.get("orderid"))
                break
            else:
                logger.info("支付方%s|%s未收到下游成功应答|订单号%s", i, outer_orderno, data.get("orderid"))
                await asyncio.sleep(10 * (i + 1))


async def noti_task(data, redis):
    await asyncio.sleep(20)
    n = 0
    while n < 100:
        obj = await db.rechange.find_one(data)
        try:
            orderstate, message, extra = await query(data, db, redis)
            logger.info("%s|%s|%s|%s", obj['ordernumber'], obj.get("payorderno"), orderstate, message)
        except Exception as e:
            logger.error(e, exc_info=True)
            n += 1
            await asyncio.sleep(20)
            continue
        if orderstate in ("0", "1"):
            # if orderstate == '0':
            #     balance = await redis.hget(obj['merchantuid'], 'balance')
            #     rate = await redis.hget(obj['merchantuid'], 'rate')
            #     balance = float(balance) - (float(obj['amount']) * float(rate))
            #     redis.hset(obj['merchantuid'], 'balance', balance)
            phone_url = obj.get("backurl")
            pay_url = obj.get("pay_backurl")
            loop.create_task(noti_user(phone_url, obj['merchantid'], obj, orderstate, message))
            if pay_url:
                loop.create_task(noti_user(pay_url, obj['merchantuid'], obj, orderstate, message))
            break
        else:
            n += 1
            logger.info('%s|第%s次查询', obj['ordernumber'], n)
            await asyncio.sleep(20)


async def periodic(proxy_redis):
    orderlist = await aioredis.create_redis(address=('localhost', 6379), loop=loop)
    while True:
        try:
            data = await orderlist.brpop('recharge', encoding='utf-8')
            obj = json.loads(data[1].replace("'", '"'))
            logger.info("开始查询%s", obj['ordernumber'])
            loop.create_task(noti_task(obj, proxy_redis))
        except Exception as e:
            logger.info(e)
            await asyncio.sleep(1)
            continue
    # else:
    #     orderlist.close()
    #     await orderlist.wait_closed()


if __name__ == '__main__':
    loop = asyncio.get_event_loop()

    logger = init_logger('cmcc', '/app/log/cs_notify/query%s.log' % sys.argv[1])
    redis = loop.run_until_complete(
            aioredis.create_redis(address=('localhost', 6379), loop=loop)
        )
    task = asyncio.Task(periodic(redis))
    client = motor.motor_tornado.MotorClient('mongodb://cs_user:cmcc5188@localhost:12018/cs_recharge')
    db = client.cs_recharge
    loop.run_forever()
